home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / MacWT 0.04 / wt / worldfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-31  |  9.6 KB  |  378 lines  |  [TEXT/MMCC]

  1. /*
  2. **  wt -- a 3d game engine
  3. **
  4. **  Copyright (C) 1994 by Chris Laurel
  5. **  email:  claurel@mr.net
  6. **  snail mail:  Chris Laurel, 5700 W Lake St #208,  St. Louis Park, MN  55416
  7. **
  8. **  This program is free software; you can redistribute it and/or modify
  9. **  it under the terms of the GNU General Public License as published by
  10. **  the Free Software Foundation; either version 2 of the License, or
  11. **  (at your option) any later version.
  12. **
  13. **  This program is distributed in the hope that it will be useful,
  14. **  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. **  GNU General Public License for more details.
  17. **
  18. **  You should have received a copy of the GNU General Public License
  19. **  along with this program; if not, write to the Free Software
  20. **  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22.  
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27. #include <limits.h>
  28. #include <math.h>
  29.  
  30. #include "wt.h"
  31. #include "error.h"
  32. #include "fixed.h"
  33. #include "wtmem.h"
  34. #include "list.h"
  35. #include "table.h"
  36. #include "texture.h"
  37. #include "world.h"
  38. #include "worldfile.h"
  39.  
  40.  
  41. #define TEXTURE_NAME_MAX_LENGTH 32
  42. #define STRING_TOKEN_MAX_LENGTH 256
  43.  
  44. #define IS_STRING_TOKEN_CHAR(c) (isalpha(c) || isdigit(c) || \
  45.                  (c) == '/' || c == '.')
  46. #define COMMENT_CHAR ';'
  47.  
  48. typedef struct {
  49.      char name[TEXTURE_NAME_MAX_LENGTH + 1];
  50.      int index;
  51. } Texture_node;
  52.  
  53. typedef enum {
  54.      Token_string,
  55.      Token_real,
  56.      Token_integer,
  57.      Token_EOF
  58. } Token_type;
  59.  
  60.  
  61. static void parse_world(FILE *fp, World *w);
  62. static void parse_vertex(FILE *fp, World *w);
  63. static void parse_wall(FILE *fp, World *w);
  64. static void parse_region(FILE *fp, World *w);
  65. static void parse_texture(FILE *fp, World *w);
  66. static int get_texture_index(char *name);
  67. static List_result find_list_name(void *node, void *data);
  68. static Token_type get_string_token(FILE *fp, char *tokenbuf);
  69. static Token_type get_real_token(FILE *fp, fixed *f);
  70. static Token_type get_integer_token(FILE *fp, int *i);
  71. static int skip_whitespace(FILE *fp);
  72. static void parse_error(char *message);
  73.  
  74. static List *texture_list;
  75. static int line_number;
  76.  
  77.  
  78. World *read_world_file(FILE *fp)
  79. {
  80.      World *w;
  81.  
  82.      w = new_world();
  83.      texture_list = new_list();
  84.      parse_world(fp, w);
  85.      delete_list(texture_list);
  86.  
  87.      return w;
  88. }
  89.  
  90.  
  91. void parse_world(FILE *fp, World *w)
  92. {
  93.      char tokenbuf[STRING_TOKEN_MAX_LENGTH];
  94.  
  95.      while (get_string_token(fp, tokenbuf) != Token_EOF) {
  96.       if (strcmp(tokenbuf, "texture") == 0)
  97.            parse_texture(fp, w);
  98.       else if (strcmp(tokenbuf, "wall") == 0)
  99.            parse_wall(fp, w);
  100.       else if (strcmp(tokenbuf, "region") == 0)
  101.            parse_region(fp, w);
  102.       else if (strcmp(tokenbuf, "vertex") == 0)
  103.            parse_vertex(fp, w);
  104.       else
  105.            parse_error("unknown structure type");
  106.      }
  107. }
  108.  
  109.  
  110. void parse_vertex(FILE *fp, World *w)
  111. {
  112.      Vertex v;
  113.  
  114.  
  115.      if (get_real_token(fp, &v.x) != Token_real)
  116.       parse_error("number expected");
  117.      if (get_real_token(fp, &v.y) != Token_real)
  118.       parse_error("number expected");
  119.  
  120.      add_vertex(w, &v);
  121. }
  122.  
  123.  
  124. void parse_region(FILE *fp, World *w)
  125. {
  126.      char texture_name[STRING_TOKEN_MAX_LENGTH];
  127.      int texture_index;
  128.      Region r;
  129.  
  130.      if (get_real_token(fp, &r.floor) != Token_real)
  131.       parse_error("number expected");
  132.      if (get_real_token(fp, &r.ceiling) != Token_real)
  133.       parse_error("number expected");
  134.  
  135.      /* floor texture */
  136.      if (get_string_token(fp, texture_name) != Token_string)
  137.       parse_error("texture name expected");
  138.      texture_index = get_texture_index(texture_name);
  139.      if (texture_index < 0 || texture_index > TABLE_SIZE(w->textures))
  140.       parse_error("non-existent texture");
  141.      else
  142.       r.floor_tex = WORLD_TEXTURE(w, texture_index);
  143.  
  144.      /* ceiling texture */
  145.      if (get_string_token(fp, texture_name) != Token_string)
  146.       parse_error("texture name expected");
  147.      if (strcmp(texture_name, "sky") == 0)
  148.       r.ceiling_tex = NULL;
  149.      else {
  150.       texture_index = get_texture_index(texture_name);
  151.       if (texture_index < 0 || texture_index > TABLE_SIZE(w->textures))
  152.            parse_error("non-existent texture");
  153.       else
  154.            r.ceiling_tex = WORLD_TEXTURE(w, texture_index);
  155.      }
  156.  
  157.      add_region(w, &r);
  158. }
  159.  
  160.  
  161. void parse_wall(FILE *fp, World *w)
  162. {
  163.      Wall wall;
  164.      char texture_name[STRING_TOKEN_MAX_LENGTH];
  165.      int texture_index;
  166.      int front_region, back_region;
  167.      int vertex1, vertex2;
  168.      fixed wall_length;
  169.  
  170.  
  171.      /* vertices */
  172.      if (get_integer_token(fp, &vertex1) != Token_integer)
  173.       parse_error("integer expected");
  174.      if (get_integer_token(fp, &vertex2) != Token_integer)
  175.       parse_error("integer expected");
  176.      if (vertex1 < 0 || vertex1 > TABLE_SIZE(w->vertices))
  177.       parse_error("invalid vertex number");
  178.      if (vertex2 < 0 || vertex2 > TABLE_SIZE(w->vertices))
  179.       parse_error("invalid vertex number");
  180.      wall.vertex1 = &WORLD_VERTEX(w, vertex1);
  181.      wall.vertex2 = &WORLD_VERTEX(w, vertex2);
  182.  
  183.      /* texture */
  184.      if (get_string_token(fp, texture_name) != Token_string)
  185.       parse_error("texture name expected");
  186.      texture_index = get_texture_index(texture_name);
  187.      if (texture_index < 0 || texture_index > TABLE_SIZE(w->textures))
  188.       parse_error("non-existent texture");
  189.      else
  190.       wall.surface_texture = WORLD_TEXTURE(w, texture_index);
  191.  
  192.      if (strcmp(texture_name, "sky") == 0)
  193.       wall.sky = True;
  194.      else
  195.       wall.sky = False;
  196.  
  197.      /* front and back regions */
  198.      if (get_integer_token(fp, &front_region) != Token_integer)
  199.       fatal_error("non-existent region");
  200.      if (get_integer_token(fp, &back_region) != Token_integer)
  201.       fatal_error("non-existent region");
  202.      if (front_region < 0 || front_region > TABLE_SIZE(w->regions))
  203.       fatal_error("non-existent region");
  204.      if (back_region < 0 || back_region > TABLE_SIZE(w->regions))
  205.       fatal_error("non-existent region");
  206.      wall.front = &WORLD_REGION(w, front_region);
  207.      wall.back = &WORLD_REGION(w, back_region);
  208.  
  209.      /* Texture phase and scale.  This code is somewhat more complicated than
  210.      **   you'd expect, since the texture scale must be normalized to the
  211.      **   wall length.
  212.      */
  213.      if (get_real_token(fp, &wall.xscale) != Token_real)
  214.       parse_error("number expected");
  215.      if (get_real_token(fp, &wall.yscale) != Token_real)
  216.       parse_error("number expected");
  217.      if (get_real_token(fp, &wall.xphase) != Token_real)
  218.       parse_error("number expected");
  219.      if (get_real_token(fp, &wall.yphase) != Token_real)
  220.       parse_error("number expected");
  221.      wall_length =
  222.       FLOAT_TO_FIXED(sqrt(FIXED_TO_FLOAT(wall.vertex2->x -
  223.                          wall.vertex1->x) *
  224.                   FIXED_TO_FLOAT(wall.vertex2->x -
  225.                          wall.vertex1->x) +
  226.                   FIXED_TO_FLOAT(wall.vertex2->y -
  227.                          wall.vertex1->y) *
  228.                   FIXED_TO_FLOAT(wall.vertex2->y -
  229.                          wall.vertex1->y)));
  230.      wall.yscale = fixmul(wall.yscale,
  231.               INT_TO_FIXED(wall.surface_texture->height));
  232.      wall.xscale = fixmul(fixmul(wall.xscale,
  233.                  INT_TO_FIXED(wall.surface_texture->width)),
  234.               wall_length);
  235.  
  236.      add_wall(w, &wall);
  237. }
  238.  
  239.  
  240. void parse_texture(FILE *fp, World *w)
  241. {
  242.      char texture_name[STRING_TOKEN_MAX_LENGTH];
  243.      char filename[STRING_TOKEN_MAX_LENGTH];
  244.      char texture_path[PATH_MAX + STRING_TOKEN_MAX_LENGTH];
  245.      Texture *t;
  246.      Texture_node *tn;
  247.  
  248.  
  249.      if (get_string_token(fp, texture_name) != Token_string)
  250.       parse_error("texture name expected");
  251.      if (strlen(texture_name) >= TEXTURE_NAME_MAX_LENGTH)
  252.       parse_error("texture name too long");
  253.  
  254.      if (get_string_token(fp, filename) != Token_string)
  255.       parse_error("texture file name expected");
  256.  
  257.      sprintf(texture_path, HostDirFileStr, TEXTURE_PATH, filename);
  258.      t = read_texture_file(texture_path);
  259.  
  260.      tn = wtmalloc(sizeof(Texture_node));
  261.      strcpy(tn->name, texture_name);
  262.      tn->index = TABLE_SIZE(w->textures);
  263.  
  264.      add_node(texture_list, tn);
  265.      add_texture(w, t);
  266. }
  267.          
  268.  
  269. int get_texture_index(char *name)
  270. {
  271.      List *l;
  272.  
  273.      l = scan_list(texture_list, name, find_list_name);
  274.      if (l == NULL)
  275.       return -1;
  276.      else
  277.       return ((Texture_node *) l->next->node)->index;
  278. }
  279.  
  280.  
  281. List_result find_list_name(void *node, void *data)
  282. {
  283.      char *name = (char *) data;
  284.      Texture_node *tnode = (Texture_node *) node;
  285.      
  286.      if (strcmp(name, tnode->name) == 0)
  287.       return List_success;
  288.      else
  289.       return List_failure;
  290. }
  291.  
  292.      
  293. Token_type get_string_token(FILE *fp, char *tokenbuf)
  294. {
  295.      int length = 0;
  296.      int c;
  297.  
  298.      c = skip_whitespace(fp);
  299.      if (c == EOF)
  300.       return Token_EOF;
  301.  
  302.      while (c != EOF && IS_STRING_TOKEN_CHAR(c)) {
  303.       if (length >= STRING_TOKEN_MAX_LENGTH - 1)
  304.            parse_error("string too long");
  305.  
  306.       tokenbuf[length] = c;
  307.       length++;
  308.  
  309.       c = getc(fp);
  310.      }
  311.  
  312.      ungetc(c, fp);
  313.      tokenbuf[length] = '\0';
  314.  
  315.      return Token_string;
  316. }
  317.  
  318.  
  319. Token_type get_real_token(FILE *fp, fixed *f)
  320. {
  321.      double d;
  322.      int c;
  323.  
  324.      c = skip_whitespace(fp);
  325.      if (c == EOF)
  326.       return Token_EOF;
  327.  
  328.      ungetc(c, fp);
  329.      if (fscanf(fp, "%lf", &d) != 1)
  330.       parse_error("numeric constant expected");
  331.  
  332.      *f = FLOAT_TO_FIXED(d);
  333.  
  334.      return Token_real;
  335. }
  336.  
  337.  
  338. Token_type get_integer_token(FILE *fp, int *i)
  339. {
  340.      int c;
  341.  
  342.      c = skip_whitespace(fp);
  343.      if (c == EOF)
  344.       return Token_EOF;
  345.  
  346.      ungetc(c, fp);
  347.      if (fscanf(fp, "%d", i) != 1)
  348.       parse_error("integer constant expected");
  349.  
  350.      return Token_integer;
  351. }
  352.  
  353.       
  354. int skip_whitespace(FILE *fp)
  355. {
  356.      int c = getc(fp);
  357.  
  358.      while (c == ' ' || c == '\t' || c == '\n' || c == COMMENT_CHAR) {
  359.       if (c == COMMENT_CHAR) {
  360.            while (c != EOF && c != '\n')
  361.             c = getc(fp);
  362.       }
  363.  
  364.       if (c == '\n')
  365.            line_number++;
  366.       c = getc(fp);
  367.      }
  368.  
  369.      return c;
  370. }
  371.  
  372.  
  373. void parse_error(char *message)
  374. {
  375.      fatal_error("Error in world file (line %d):  %s\n", line_number,
  376.          message);
  377. }
  378.